package tech.mhuang.pacebox.springboot.autoconfiguration;

import io.undertow.Undertow;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import tech.mhuang.pacebox.core.id.BaseIdeable;
import tech.mhuang.pacebox.core.id.SnowflakeIdeable;
import tech.mhuang.pacebox.springboot.autoconfiguration.auth.AuthAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.cors.InterCorsAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.cors.InterReactorCorsAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.datasecure.DataSecureAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.elasticsearch.ESAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.exception.ExceptionAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.jackson.InterJacksonAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.jwt.JwtAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.kafka.KafkaAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.oss.OssAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.permission.PermissionAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.redis.RedisExtAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.rest.RestAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.sms.SmsAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.swagger.SwaggerAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.task.TaskAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.trace.TraceAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.validate.ValidationAutoConfiguration;
import tech.mhuang.pacebox.springboot.autoconfiguration.web.UndertowServerFactoryCustomizer;
import tech.mhuang.pacebox.springboot.autoconfiguration.wechat.WechatAutoConfiguration;
import tech.mhuang.pacebox.springboot.core.event.ApplicationClosedEventListener;
import tech.mhuang.pacebox.springboot.core.servlet.RequestFilter;
import tech.mhuang.pacebox.springboot.core.spring.start.SpringContextHolder;

/**
 * 自动配置注入包.
 *
 * @author mhuang
 * @since 1.0.0
 */
@Configuration
@Import({InterCorsAutoConfiguration.class, InterReactorCorsAutoConfiguration.class,
        RestAutoConfiguration.class,
        RedisExtAutoConfiguration.class, SwaggerAutoConfiguration.class,
        DataSecureAutoConfiguration.class,
        AuthAutoConfiguration.class,
        TaskAutoConfiguration.class,
        InterJacksonAutoConfiguration.class, JwtAutoConfiguration.class,
        ESAutoConfiguration.class,
        KafkaAutoConfiguration.class, TraceAutoConfiguration.class,
        SmsAutoConfiguration.class, OssAutoConfiguration.class,
        ValidationAutoConfiguration.class,
        ExceptionAutoConfiguration.class, WechatAutoConfiguration.class,
        PermissionAutoConfiguration.class,
})
@EnableConfigurationProperties(value = SpringBootExtProperties.class)
@ConditionalOnProperty(prefix = ConfigConsts.SPRINGBOOT, name = ConfigConsts.ENABLE, havingValue = ConfigConsts.TRUE)
public class SpringBootExtAutoConfiguration {

    private final SpringBootExtProperties properties;

    public SpringBootExtAutoConfiguration(SpringBootExtProperties properties) {
        this.properties = properties;
    }

    @Bean
    @Order(Integer.MIN_VALUE + 1)
    public FilterRegistrationBean<RequestFilter> requestRegisterBean() {
        RequestFilter requestFilter = new RequestFilter();
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(requestFilter);
        registration.setOrder(Integer.MIN_VALUE);
        registration.addUrlPatterns("/*");
        registration.setName("RequestFilter");
        return registration;
    }

    /**
     * create context process tool
     *
     * @return SpringContextHolder
     */
    @Bean
    @ConditionalOnMissingBean
    public SpringContextHolder springContextHolder() {
        return new SpringContextHolder();
    }

    /**
     * create generator id.
     * default used snowflake
     *
     * @return BaseIdeable
     */
    @Bean
    @ConditionalOnMissingBean
    public BaseIdeable<String> snowflake() {
        return new SnowflakeIdeable();
    }

    @ConditionalOnProperty(prefix = ConfigConsts.SPRINGBOOT,name = ConfigConsts.STOP_ENABLE, havingValue = ConfigConsts.TRUE,matchIfMissing = true)
    @Bean
    @ConditionalOnMissingBean
    public ApplicationClosedEventListener applicationClosedEventListener(){
        return new ApplicationClosedEventListener();
    }
    /**
     * undertow警告去除
     *
     * @since 2021.0.5.0
     */
    @ConditionalOnBean(UndertowServletWebServerFactory.class)
    public static final class WebMvcConfig {
        @Bean
        @ConditionalOnClass(Undertow.class)
        public UndertowServerFactoryCustomizer getUndertowServerFactoryCustomizer() {
            return new UndertowServerFactoryCustomizer();
        }
    }
}